#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<hs/hs.h>

// 宏定义
#define MAXNUM 1000

typedef struct closest{
    int sno[MAXNUM];
    int mno;
    int cnt;
}closest_t;

// 匹配回调函数
static int on_match(unsigned int id, unsigned long long from,
        unsigned long long to, unsigned int flags, void *ctx);
 // 查找亲近同学
void find_closest_classmate(closest_t *, const char *, const char *);
void output(closest_t *); // 输出结果

// 测试
int main()
{
    // 声明变量
    int mno;
    char like[27]; // 26个大写字符+'\0'
    char classmate[MAXNUM + 1];  // MAXNUM个同学+'\0'
    closest_t c_stu = {{-1}, -1, -1};

    mno = 1;
    c_stu.mno = mno;
    strcpy(like, "ABC");
    strcpy(classmate, "BPTYHJKAMNBPHC");

    // 处理数据
    find_closest_classmate(&c_stu, like, classmate);

    // 输出结果
    output(&c_stu);

    return 0;
}

// 查找亲近同学
void find_closest_classmate(closest_t *c_stu, const char *like,
                            const char *classmate)
{
    // 构造正则表达式
    char *pat = (char*)malloc((strlen(like) + 2 + 1) * sizeof(char));
    if(pat == NULL)
    {
        printf("not enough memory!\n");
        exit(EXIT_FAILURE);
    }

    // 正则表达式(注意添加小括号分组)
    memset(pat, 0, (strlen(like) + 2 + 1) * sizeof(char));
    strcat(pat, "[");
    strcat(pat, like);
    strcat(pat, "]");

    // 正则对象指针
    hs_database_t *db = NULL;
    hs_compile_error_t *compile_err = NULL;

    // 编译正则表达式
    if(hs_compile(pat, HS_FLAG_SOM_LEFTMOST | HS_FLAG_DOTALL, HS_MODE_BLOCK,
                  NULL, &db, &compile_err) != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to compile pattern \"%s\": %s\n",
                pat, compile_err->message);
        hs_free_compile_error(compile_err);
        exit(EXIT_FAILURE);
    }

    // 申请临时空间
    hs_scratch_t *scratch = NULL;
    if(hs_alloc_scratch(db, &scratch) != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to allocate scratch space."
                        " Exiting.\n");
        hs_free_database(db);
        exit(EXIT_FAILURE);
    }

    // 正则匹配
    if(hs_scan(db, classmate, strlen(classmate), 0, scratch, on_match, c_stu)
            != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to scan input buffer."
                        " Exiting.\n");
        hs_free_scratch(scratch);
        hs_free_database(db);
        exit(EXIT_FAILURE);
    }

    // 释放空间
    hs_free_scratch(scratch);
    hs_free_database(db);

    free(pat);
}

// 输出结果
void output(closest_t *c_stu)
{
    int i;

    if(c_stu->cnt > 0)
    {
        for(i = 0; i < c_stu->cnt; i++)
        {
            printf("%d ", c_stu->sno[i]);
        }
        printf("%d\n", c_stu->sno[i]); // 避免最后输出多1个空格
    }
    else
    {
        printf("Lonely Xiao Ming\n");
    }
}

static int on_match(unsigned int id, unsigned long long from,
        unsigned long long to, unsigned int flags, void *ctx)
{
    closest_t *c_stu = (closest_t *)ctx;

    // 只记录与自己学号不同的朋友(地址相减)
    if((from + 1) != c_stu->mno)
    {
        c_stu->cnt++;
        c_stu->sno[c_stu->cnt] = from + 1;
    }

    return 0; // 返回0继续匹配， 返回1结束匹配
}
